/*=============================================================================
# FileName    :	axi4_drive.sv
# Author      :	author
# Email       :	email@email.com
# Description :	本驱动对axi4和axi4-lite协议通用，但需注意burst相关task不支持axi4-lite
# Version     :	1.0
# LastChange  :	2018-04-03 22:22:23
# ChangeLog   :	
=============================================================================*/
`ifndef axi4_DRIVE_H
`define axi4_DRIVE_H

class axi4_drive;
    virtual axi4_bfm    bfm;
    //rand bit [31:00] data;

    //constraint c
    //{
        //data.size() == 5;
        //foreach(data[i])
            //data[i] inside {[0:65535]};
    //}

    function new(virtual axi4_bfm b);
        bfm = b;
    endfunction
    /*-------------------------------------------------------------------------
    //description   :   初始化axi4-lite接口信号
    -------------------------------------------------------------------------*/
    extern task init();
    /*-------------------------------------------------------------------------
    //description   :   配置写操作相关参数
    -------------------------------------------------------------------------*/
    extern task write_config
        (   
            input bit [3:0] wlen = 0,
            input bit [2:0] wsize = 3'b010,
            input bit [1:0] wburst = 2'b01
        );
    /*-------------------------------------------------------------------------
    //description   :   配置读操作相关参数
    -------------------------------------------------------------------------*/
    extern task read_config();
    /*-------------------------------------------------------------------------
    //description   :   指定位置写入一个单位数据
    //addr指的是以字节为单位的地址, axi4 lite slave器件数据宽度至少为32bit
    //所以地址步增至少为4的倍数
    -------------------------------------------------------------------------*/
    extern task write_dword(int addr, bit [31:00] data);
    /*-------------------------------------------------------------------------
    //description   :   指定位置写入len长度单位数据
    -------------------------------------------------------------------------*/
    extern task write_burst(int addr, int len);
    extern task read_dword(int addr);
    extern task read_burst(int addr, int len);
endclass

task axi4_drive::init();
    bfm.s_axi_awid = 0;
    bfm.s_axi_awaddr = 0;
    bfm.s_axi_awvalid = 0;
    bfm.s_axi_wdata = 0;
    bfm.s_axi_wstrb = 0;
    bfm.s_axi_wlast = 0;
    bfm.s_axi_wvalid = 0;
    bfm.s_axi_bready = 1;
    bfm.s_axi_awlock = 0;
    bfm.s_axi_awcache = 0;
    bfm.s_axi_awprot = 0;


    bfm.s_axi_arid = 0;
    bfm.s_axi_araddr = 0;
    bfm.s_axi_arlen = 0;
    bfm.s_axi_arsize = 0;
    bfm.s_axi_arburst = 0;
    bfm.s_axi_arvalid = 0;
    bfm.s_axi_rready = 0;
    bfm.s_axi_arlock = 0;
    bfm.s_axi_arcache = 0;
    bfm.s_axi_arprot = 0;
    
endtask

/*-------------------------------------------------------------------------
//description   : 配置axi4-lite写slave相关参数
//parameter     :
//others        :
-------------------------------------------------------------------------*/
task axi4_drive::write_config
(   // 缺省参数
    input bit [3:0] wlen = 0,
    input bit [2:0] wsize = 3'b010,
    input bit [1:0] wburst = 2'b01
);
    bfm.s_axi_awlen = wlen;
    bfm.s_axi_awsize = wsize;
    bfm.s_axi_awburst = wburst;
endtask

/*-------------------------------------------------------------------------
//description   : 配置axi4-lite 读slave相关参数
//parameter     :
//others        :
-------------------------------------------------------------------------*/
task axi4_drive::read_config();
    bfm.s_axi_arlen = 0;
    bfm.s_axi_arsize = 3'b010;
    bfm.s_axi_arburst = 2'b01;
endtask

/*-------------------------------------------------------------------------
//description   : 向指定地址写入一个dword（相当于burst一个单位）
//parameter     : addr, slave器件reg地址
//parameter     : data, 要写入的地址
//others        :
-------------------------------------------------------------------------*/
task axi4_drive::write_dword(int addr, bit [31:00] data);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_awid = 0;
    bfm.s_axi_wstrb = 4'b1111;

    bfm.s_axi_awvalid = 1;
    bfm.s_axi_awaddr = addr;
    bfm.s_axi_wdata = data;
    //bfm.s_axi_wvalid = 1;
    bfm.s_axi_wlast = 0;

    wait (bfm.s_axi_awready);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_awvalid = 0;

    @ (posedge bfm.s_aclk);
    bfm.s_axi_wvalid = 1;
    bfm.s_axi_wlast = 1;
    wait (bfm.s_axi_wready);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_awvalid = 0;
    bfm.s_axi_awaddr = 0;
    bfm.s_axi_wdata = 0;
    bfm.s_axi_wvalid = 0;
    bfm.s_axi_wlast = 0;

    wait (bfm.s_axi_bready & bfm.s_axi_bvalid);
/*
    fork
        begin
            wait(bfm.s_axi_awready)
            @ (posedge bfm.s_aclk);
            bfm.s_axi_awvalid = 0;
            bfm.s_axi_awaddr = 0;
        end
    join
        begin
            bfm.s_axi_wvalid = 1;
            wait(bfm.s_axi_wready)
            bfm.s_axi_wdata = 0;
            bfm.s_axi_wvalid = 0;
            bfm.s_axi_wlast = 0;
        end
        */

endtask

/*-------------------------------------------------------------------------
//description   : burst写slave器件
//parameter     : addr, slave器件reg地址.地址需要边界对其
//parameter     : len, 突发写的长度
//others        : 写地址和写数据通道同时工作，写入随机数据
//                不支持axi4-lite协议
-------------------------------------------------------------------------*/
task axi4_drive::write_burst(int addr, int len);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_awid = 0;
    bfm.s_axi_wstrb = 4'b1111;

    bfm.s_axi_awlen = len - 1;
    bfm.s_axi_awvalid = 1;
    bfm.s_axi_awaddr = addr;
    //bfm.s_axi_wdata = data;
    //bfm.s_axi_wvalid = 1;
    bfm.s_axi_wlast = 0;

    fork
        begin
            wait(bfm.s_axi_awready)
            @ (posedge bfm.s_aclk);
            bfm.s_axi_awvalid = 0;
            bfm.s_axi_awaddr = 0;
        end
    join/*_any or _none*/
        begin
            bfm.s_axi_wvalid = 1;
            wait(bfm.s_axi_wready)
            for(int i = 0; i < len; i = i + 1 )
            begin
                bfm.s_axi_wdata = $urandom_range(0, 65535);
                if(i == len-1)
                    bfm.s_axi_wlast = 1;
                @ (posedge bfm.s_aclk);
            end
            bfm.s_axi_wdata = 0;
            bfm.s_axi_wvalid = 0;
            bfm.s_axi_wlast = 0;
        end
endtask

/*-------------------------------------------------------------------------
//description   : 从slave指定addr读取一个单位的数据
//parameter     : addr, slave器件reg地址
//others        :
-------------------------------------------------------------------------*/
task axi4_drive::read_dword(int addr);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_arid = 0;
    bfm.s_axi_araddr = addr;
    bfm.s_axi_arlen = 0;
    bfm.s_axi_arvalid = 1;
    wait (bfm.s_axi_arready);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_arvalid = 0;

    bfm.s_axi_rid = 1;
    bfm.s_axi_rready = 1;
    wait (bfm.s_axi_rvalid);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_rready = 0;
endtask

/*-------------------------------------------------------------------------
//description   : 从slave指定addr读取len长度单位的数据
//parameter     : addr, slave器件reg地址
//others        :
-------------------------------------------------------------------------*/
task axi4_drive::read_burst(int addr, int len);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_arid = 0;
    bfm.s_axi_araddr = addr;
    bfm.s_axi_arlen = len-1;
    bfm.s_axi_arvalid = 1;

    wait (bfm.s_axi_arready);
    @ (posedge bfm.s_aclk);
    bfm.s_axi_arvalid = 0;
    bfm.s_axi_araddr = 0;

    bfm.s_axi_rready = 1;
    wait (bfm.s_axi_rready);
    repeat(len)
    begin
        @ (posedge bfm.s_aclk);
    end
    bfm.s_axi_rready = 0;
endtask

`endif
